<div class="tmd-doc">
<h1 class="tmd-header-1">
More about Deferred Function Calls
</h1>
<p></p>
<div class="tmd-usual">
Deferred function calls have been <a href="control-flows-more.html#defer">introduced before</a>. Due to the limited Go knowledge at that time, some more details and use cases of deferred functions calls are not touched in that article. These details and use cases will be touched in the remaining of this article.
</div>
<p></p>
<p></p>
<h3 class="tmd-header-3">
Calls to Many Built-in Functions With Return Results Can't Be Deferred
</h3>
<p></p>
<div class="tmd-usual">
In Go, the result values of a call to custom functions can be all absent (discarded). However, for built-in functions with non-blank return result lists, the result values of their calls <a href="exceptions.html#discard-return-results">mustn't be absent</a>, except the calls to the built-in <code class="tmd-code-span">copy</code> and <code class="tmd-code-span">recover</code> functions. On the other hand, we have learned that the result values of a deferred function call must be discarded, so the calls to many built-in functions can't be deferred.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
Fortunately, the needs to defer built-in function calls (with non-blank return result lists) are rare in practice. As far as I know, only the calls to the built-in <code class="tmd-code-span">append</code> function may needed to be deferred sometimes. For this case, we can defer a call to an anonymous function which wraps the <code class="tmd-code-span">append</code> call.
</div>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

import "fmt"

func main() {
	s := []string{"a", "b", "c", "d"}
	defer fmt.Println(s) // [a x y d]
	// defer append(s[:1], "x", "y") // error
	defer func() {
		_ = append(s[:1], "x", "y")
	}()
}
</code></pre>
<p></p>
<h3 id="function-evaluation-time" class="tmd-header-3">
The Evaluation Moment of Deferred Function Values
</h3>
<p></p>
<div class="tmd-usual">
The called function (value) in a deferred function call is evaluated when the call is pushed into the defer-call stack of the current goroutine. For example, the following program will print <code class="tmd-code-span">false</code>.
</div>
<p></p>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

import "fmt"

func main() {
	var f = func () {
		fmt.Println(false)
	}
	defer f()
	f = func () {
		fmt.Println(true)
	}
}
</code></pre>
<p></p>
<div class="tmd-usual">
The called function in a deferred function call may be a nil function value. For such a case, the panic will occur when the call to the nil function is invoked, instead of when the call is pushed into the defer-call stack of the current goroutine. An example:
</div>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

import "fmt"

func main() {
	defer fmt.Println("reachable 1")
	var f func() // f is nil by default
	defer f()    // panic here
	// The following lines are also reachable.
	fmt.Println("reachable 2")
	f = func() {} // useless to avoid panicking
}
</code></pre>
<p></p>
<h3 class="tmd-header-3">
The Evaluation Moment of Receiver Arguments of Deferred Method Calls
</h3>
<p></p>
<div class="tmd-usual">
As explained before, the arguments of a deferred function call are <a href="control-flows-more.html#argument-evaluation-moment">also evaluated when</a> the deferred call is pushed into the defer-call stack of the current goroutine.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
Method receiver arguments are also not exceptions. For example, the following program prints <code class="tmd-code-span">1342</code>.
</div>
<p></p>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

type T int

func (t T) M(n int) T {
  print(n)
  return t
}

func main() {
	var t T
	// "t.M(1)" is the receiver argument of the method
	// call ".M(2)", so it is evaluated when the
	// ".M(2)" call is pushed into defer-call stack.
	defer t.M(1).M(2)
	t.M(3).M(4)
}
</code></pre>
<p></p>
<h3 class="tmd-header-3">
Deferred Calls Make Code Cleaner and Less Bug Prone
</h3>
<p></p>
<div class="tmd-usual">
Example:
</div>
<p></p>
<pre class="tmd-code line-numbers">
<code class="language-go">import "os"

func withoutDefers(filepath string, head, body []byte) error {
	f, err := os.Open(filepath)
	if err != nil {
		return err
	}

	_, err = f.Seek(16, 0)
	if err != nil {
		f.Close()
		return err
	}

	_, err = f.Write(head)
	if err != nil {
		f.Close()
		return err
	}

	_, err = f.Write(body)
	if err != nil {
		f.Close()
		return err
	}

	err = f.Sync()
	f.Close()
	return err
}

func withDefers(filepath string, head, body []byte) error {
	f, err := os.Open(filepath)
	if err != nil {
		return err
	}
	defer f.Close()

	_, err = f.Seek(16, 0)
	if err != nil {
		return err
	}

	_, err = f.Write(head)
	if err != nil {
		return err
	}

	_, err = f.Write(body)
	if err != nil {
		return err
	}

	return f.Sync()
}
</code></pre>
<p></p>
<p></p>
<div class="tmd-usual">
Which one looks cleaner? Apparently, the one with the deferred calls, though a little. And it is less bug prone, for there are so many <code class="tmd-code-span">f.Close()</code> calls in the function without deferred calls that it has a higher possibility to miss one of them.
</div>
<p></p>
<div class="tmd-usual">
The following is another example to show deferred calls can make code less bug prone. If the <code class="tmd-code-span">doSomething</code> calls panic in the following example, the function <code class="tmd-code-span">f2</code> will exit without unlocking the <code class="tmd-code-span">Mutex</code> value. So the function <code class="tmd-code-span">f1</code> is less bug prone.
</div>
<p></p>
<pre class="tmd-code line-numbers">
<code class="language-go">var m sync.Mutex

func f1() {
	m.Lock()
	defer m.Unlock()
	doSomething()
}

func f2() {
	m.Lock()
	doSomething()
	m.Unlock()
}
</code></pre>
<p></p>
<h3 class="tmd-header-3">
Performance Losses Caused by Deferring Function Calls
</h3>
<p></p>
<div class="tmd-usual">
It is not always good to use deferred function calls. For the official Go compiler, before version 1.13, deferred function calls will cause a few performance losses at run time. Since Go Toolchain 1.13, some common defer use cases have got optimized much, so that generally we don't need to care about the performance loss problem caused by deferred calls. Thank Dan Scales for making the great optimizations.
</div>
<p></p>
<p></p>
<h3 id="kind-of-resource-leaking" class="tmd-header-3">
Kind-of Resource Leaking by Deferring Function Calls
</h3>
<p></p>
<div class="tmd-usual">
A very large defer-call stack may also consume much memory, and some resources might not get released in time if some calls are delayed too much.
</div>
<p></p>
<div class="tmd-usual">
For example, if there are many files needed to be handled in a call to the following function, then a large number of file handlers will be not get released before the function exits.
</div>
<p></p>
<pre class="tmd-code line-numbers">
<code class="language-go">func writeManyFiles(files []File) error {
	for _, file := range files {
		f, err := os.Open(file.path)
		if err != nil {
			return err
		}
		defer f.Close()

		_, err = f.WriteString(file.content)
		if err != nil {
			return err
		}

		err = f.Sync()
		if err != nil {
			return err
		}
	}

	return nil
}
</code></pre>
<p></p>
<div class="tmd-usual">
For such cases, we can use an anonymous function to enclose the deferred calls so that the deferred function calls will get executed earlier. For example, the above function can be rewritten and improved as
</div>
<p></p>
<pre class="tmd-code line-numbers">
<code class="language-go">func writeManyFiles(files []File) error {
	for _, file := range files {
		if err := func() error {
			f, err := os.Open(file.path)
			if err != nil {
				return err
			}
			// The close method will be called at
			// the end of the current loop step.
			defer f.Close()

			_, err = f.WriteString(file.content)
			if err != nil {
				return err
			}

			return f.Sync()
		}(); err != nil {
			return err
		}
	}

	return nil
}
</code></pre>
<p></p>
</div>
